home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
video
/
fly8111-.000
/
fly8111-
/
fly8
/
COMMON
/
stick.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-28
|
13KB
|
629 lines
/* --------------------------------- stick.c -------------------------------- */
/* This is part of the flight simulator 'fly8'.
* Author: Eyal Lebedinsky (eyal@ise.canberra.edu.au).
*/
/* Handler for the PC joystick as a pointing device. On port A It will
* read the analog hat if it is present and will read all four buttons.
* Use of options:
*
* 0 analog 1 direction p,n
* 1 what analog 1 controls 0,1
* 2 analog 2 direction p,n
* 3 what analog 2 controls 0,1
* 4 number of times to read 0-36
* 5 delay between reads 0-36
* 6 analog 1 base 0-10
* 7 analog 2 base 0-10
* 8 analog 3 base 0-10
* 9 analog 4 base 0-10 (hat, throttle etc.)
*/
#include "fly.h"
#ifdef HAVE_JOYSTICK
#include "stick.h"
#define PO p->opt
#define FA1D PO[0]
#define FA1F PO[1]
#define FA2D PO[2]
#define FA2F PO[3]
#define FNREAD PO[4]
#define FDELAY PO[5]
#define FA1IDLE PO[6]
#define FA1BASE PO[7]
#define FA1TOP PO[8]
#define FA2IDLE PO[9]
#define FA2BASE PO[10]
#define FA2TOP PO[11]
#define FA3IDLE PO[12]
#define FA3BASE PO[13]
#define FA3TOP PO[14]
#define FA4IDLE PO[15]
#define FA4BASE PO[16]
#define FA4TOP PO[17]
#define FOPTS PO[18]
#define REF 100 /* expected full range */
#define REFDETENT 75 /* Fly8 AB detent position */
/* Second level joystick input: apply 'nread' and 'ndelay'.
*/
LOCAL_FUNC int NEAR
JsInput (int which, STICK *s, int opts, Ushort mask, Ushort nread,
Ushort delay)
{
Uint m, js, minx1, miny1, minx2, miny2, ntimes;
int i, t;
minx1 = miny1 = minx2 = miny2 = 0xffffU;
for (ntimes = 0;;) {
m = readstick (which, s, mask, opts);
if (minx1 > s->a[0])
minx1 = s->a[0];
if (miny1 > s->a[1])
miny1 = s->a[1];
if (minx2 > s->a[2])
minx2 = s->a[2];
if (miny2 > s->a[3])
miny2 = s->a[3];
if (++ntimes >= nread) /* read more? */
break;
if (T(i = delay)) { /* delay? */
t = 1234;
for (i *= 10; i-- > 0;)
t *= 19;
}
}
js = m | ~mask;
s->a[0] = (Ushort)((js & JS_X1) ? 0 : minx1);
s->a[1] = (Ushort)((js & JS_Y1) ? 0 : miny1);
s->a[2] = (Ushort)((js & JS_X2) ? 0 : minx2);
s->a[3] = (Ushort)((js & JS_Y2) ? 0 : miny2);
return (m);
}
/* Third level joystick input: interpret the raw input and adjust for
* calibration.
*/
/* Interpret the joystick reading as symm_etric -100...+100.
* The 'base' parameter is interpreted as a fraction of the center reading.
*/
LOCAL_FUNC void NEAR
JsSymm (POINTER *p, int channel, int reading, int sign, int base, int top,
int transfer)
{
int center;
int play;
center = p->c[channel];
play = p->play[channel];
if (reading < (base += (play >> 1)))
reading = -100;
else if (reading < (center -= play))
reading = muldiv (-100, center - reading, center - base);
else if (reading < (center += play+play))
reading = 0;
else if (reading < (top -= (play >> 1)))
reading = muldiv (100, reading - center, top - center);
else
reading = 100;
reading *= sign; /* orientation */
p->a[channel] = (short)reading;
if (transfer)
p->l[channel] = (short)((FOPTS & USELOG)
? lin2log ((short)reading) : reading);
}
/* Interpret the joystick reading as 'hat' position.
* The 'base' parameter is interpreted as a fraction of the center reading.
* the reading is spread evenly from 0 to 100 and has the following states
* in order: 0=up, 25=right, 50=down, 75=left, 100=center.
*/
LOCAL_FUNC void NEAR
JsHat (POINTER *p, int reading, int base, int top, char *btn)
{
if (reading <= base)
reading = 0;
else if (reading >= top)
reading = REF;
else
reading = muldiv (REF, reading - base, top - base);
btn[4 + (reading + REF/8)/(REF/4)] = 1;
}
/* Interpret the joystick reading as a 0-100.
* The 'base' parameter is interpreted as a fraction of the center reading.
*/
LOCAL_FUNC void NEAR
JsPos (POINTER *p, int channel, int reading, int sign, int base, int top,
int transfer)
{
int play;
play = p->play[channel];
if (reading <= (base += play))
reading = 0;
else if (reading >= (top -= play))
reading = REF;
else
reading = muldiv (REF, reading - base, top - base);
if (sign)
reading = REF - reading;
p->a[channel] = (short)reading;
if (transfer)
p->l[channel] = (short)reading;
}
LOCAL_FUNC int FAR
JsaRead (POINTER *p, int transfer)
{
STICK s[1];
int i, n;
char btn[10];
n = JS_X1|JS_Y1;
if (FOPTS & READA3)
n |= JS_Y2;
if (JsInput (0, s, FOPTS, (Ushort)n, (Ushort)FNREAD, (Ushort)FDELAY))
return (1); /* reading failed */
if (p->low[FA1F] > s->a[0])
p->low[FA1F] = s->a[0];
if (p->high[FA1F] < s->a[0])
p->high[FA1F] = s->a[0];
if (p->low[FA2F] > s->a[1])
p->low[FA2F] = s->a[1];
if (p->high[FA2F] < s->a[1])
p->high[FA2F] = s->a[1];
if (FOPTS & READA3) {
if (p->low[3] > s->a[3])
p->low[3] = s->a[3];
if (p->high[3] < s->a[3])
p->high[3] = s->a[3];
}
if (!(FOPTS & CALIBRATED))
return (0);
memset (btn, 0, sizeof (btn));
JsSymm (p, FA1F, s->a[0], -FA1D, FA1BASE, FA1TOP, transfer);
JsSymm (p, FA2F, s->a[1], FA2D, FA2BASE, FA2TOP, transfer);
if (FOPTS & READA3) {
if (FOPTS & HAT)
JsHat (p, s->a[3], FA4BASE, FA4TOP, btn);
else if (FOPTS & THROTTLE) {
JsPos (p, 3, s->a[3], FOPTS & THTDOWN,
FA4BASE, FA4TOP, transfer);
if (!transfer)
{}
else if (p->l[3] < p->c[3] - FA4IDLE)
p->l[3] = (short)(muldiv (p->l[3],
REFDETENT, p->c[3]));
else if (p->l[3] < p->c[3] + FA4IDLE)
p->l[3] = REFDETENT;
else
p->l[3] = (short)(REFDETENT
+ muldiv (REF-REFDETENT,
p->l[3] - p->c[3], REF - p->c[3]));
}
}
if (FOPTS & CHPRO) {
i = (s->b[0] << 3) | (s->b[1] << 2) | (s->b[2] << 1) | s->b[3];
switch (i) {
case 0x08:
btn[0] = 1;
break;
case 0x04:
btn[1] = 1;
break;
case 0x02:
btn[2] = 1;
break;
case 0x01:
btn[3] = 1;
break;
case 0x0c:
btn[7] = 1;
break;
case 0x0e:
btn[6] = 1;
break;
case 0x0d:
btn[5] = 1;
break;
case 0x0f:
btn[4] = 1;
break;
default:
break;
}
n = 8;
} else {
if (FOPTS & ZEROBUTTONS)
n = 0;
else {
n = (FOPTS & FOURBUTTONS) ? 4 : 2;
for (i = 0; i < n; ++i)
btn[i] = (char)s->b[i];
}
if (FOPTS & HAT) {
for (i = n; i < 4; ++i)
btn[i] = p->btn[i] & 1;
n = 8;
}
}
do_btns (p, btn, n);
return (0);
}
/* Calibrate joy-stick. Paddle and 'hat' must be at center!
*/
LOCAL_FUNC int FAR
JsaCal (POINTER *p)
{
STICK s[1];
int m;
m = JS_X1|JS_Y1;
if (FOPTS & (HAT|THROTTLE)) {
FOPTS |= READA3;
m |= JS_Y2;
}
m = JsInput (0, s, FOPTS, (Ushort)m, 10, 10);
if (m & JS_X1)
return (1);
if (!s->a[0])
return (2);
if (m & JS_Y1)
return (3);
if (!s->a[1])
return (4);
FA1BASE = p->low[FA1F];
FA1TOP = p->high[FA1F];
p->c[FA1F] = s->a[0];
p->play[FA1F] = muldiv (FA1TOP, FA1IDLE, 100);
p->a[FA1F] = p->l[FA1F] = 0;
p->low [FA1F] = 0x7fff;
p->high[FA1F] = 0x0000;
FA2BASE = p->low[FA2F];
FA2TOP = p->high[FA2F];
p->c[FA2F] = s->a[1];
p->play[FA2F] = muldiv (FA2TOP, FA2IDLE, 100);
p->a[FA2F] = p->l[FA2F] = 0;
p->low [FA2F] = 0x7fff;
p->high[FA2F] = 0x0000;
if (FOPTS & READA3) {
if ((m & JS_Y2) || !s->a[3]) {
if (FOPTS & HAT)
MsgEPrintf (50, "no analog hat");
else if (FOPTS & THROTTLE)
MsgEPrintf (50, "no analog throttle");
FOPTS &= ~READA3; /* failed */
} else if (FOPTS & HAT) {
MsgWPrintf (50, "using analog hat");
FA4BASE = p->low[3];
FA4TOP = p->high[3];
p->c[3] = s->a[3];
p->play[3] = muldiv (FA4TOP, FA4IDLE, 100);
p->low [3] = 0x7fff;
p->high[3] = 0x0000;
} else if (FOPTS & THROTTLE) {
MsgWPrintf (50, "using analog throttle");
FA4BASE = p->low[3];
FA4TOP = p->high[3];
p->play[3] = muldiv (FA4TOP, FA4IDLE, 100);
p->low [3] = 0x7fff;
p->high[3] = 0x0000;
JsPos (p, 3, s->a[3], FOPTS & THTDOWN,
FA4BASE, FA4TOP, 0);
p->c[3] = p->a[3];
p->a[3] = p->l[3] = 0;
}
}
FOPTS |= CALIBRATED;
return (0);
}
LOCAL_FUNC void NEAR
JsOptions (POINTER *p, char *options)
{
long l;
if (get_arg (options, "count"))
FOPTS &= ~USETIMER;
if (get_arg (options, "linear"))
FOPTS &= ~USELOG;
if (get_narg (options, "rd=", &l))
FNREAD = 1;
else
FNREAD = (int)l;
if (get_narg (options, "dly=", &l))
FDELAY = 1;
else
FDELAY = (int)l;
if (get_narg (options, "ix1=", &l))
FA1IDLE = 10;
else
FA1IDLE = (int)l;
if (get_narg (options, "iy1=", &l))
FA2IDLE = 10;
else
FA2IDLE = (int)l;
}
LOCAL_FUNC int FAR
JsaInit (POINTER *p, char *options)
{
int i;
long l;
int ret;
char *o;
FOPTS &= ~(HAT|THROTTLE|FOURBUTTONS|ZEROBUTTONS);
FOPTS |= USETIMER|USELOG;
JsOptions (p, options);
if (get_narg (options, "ix2=", &l))
FA3IDLE = 10;
else
FA3IDLE = (int)l;
if (get_narg (options, "iy2=", &l))
FA4IDLE = 10;
else
FA4IDLE = (int)l;
if (get_arg (options, "hat"))
FOPTS |= HAT;
else if (T(o = get_arg (options, "ttl"))) {
FOPTS |= THROTTLE;
if ('-' == *o)
FOPTS |= THTDOWN;
}
if (get_arg (options, "zero"))
FOPTS |= ZEROBUTTONS;
else if (get_arg (options, "four"))
FOPTS |= FOURBUTTONS;
else if (get_arg (options, "chpro"))
FOPTS |= CHPRO;
if (T(ret = initstick (0, options, FOPTS))) {
LogPrintf ("Astick init failed %d\n", ret);
return (ret);
}
for (i = 0; i < 4; ++i) {
p->high[i] = 0x0000;
p->low [i] = 0x7fff;
p->c [i] = 0x4000;
}
JsaCal (p); /* one for the road */
ret = JsaCal (p);
FOPTS &= ~CALIBRATED;
if (ret)
LogPrintf ("Astick cal failed %d\n", ret);
else {
MsgWPrintf (200, "Move the stick to all 4 egdes,");
MsgWPrintf (200, " then center it.");
if (FOPTS & HAT) {
MsgWPrintf (200, "Try all hat positions,");
MsgWPrintf (200, " then center it.");
}
if (FOPTS & THROTTLE) {
MsgWPrintf (200, "Move throttle to both ends,");
MsgWPrintf (200, " then set to MIL detent.");
}
MsgWPrintf (200, "now hit 'x' to callibrate.");
}
return (ret);
}
LOCAL_FUNC void FAR
JsaTerm (POINTER *p)
{
termstick (0, FOPTS);
}
LOCAL_FUNC int FAR
JsCenter (POINTER *p)
{
p->a[FA1F] = p->a[FA2F] = 0;
p->l[FA1F] = p->l[FA2F] = 0;
return (0);
}
LOCAL_FUNC int FAR
JsbRead (POINTER *p, int transfer)
{
STICK s[1];
char btn[2];
if (JsInput (1, s, FOPTS, JS_X1|JS_Y1, (Ushort)FNREAD, (Ushort)FDELAY))
return (1); /* reading failed */
if (p->low[FA1F] > s->a[0])
p->low[FA1F] = s->a[0];
if (p->high[FA1F] < s->a[0])
p->high[FA1F] = s->a[0];
if (p->low[FA2F] > s->a[1])
p->low[FA2F] = s->a[1];
if (p->high[FA2F] < s->a[1])
p->high[FA2F] = s->a[1];
if (!(FOPTS & CALIBRATED))
return (0);
memset (btn, 0, sizeof (btn));
JsSymm (p, FA1F, s->a[0], -FA1D, FA1BASE, FA1TOP, transfer);
JsSymm (p, FA2F, s->a[1], FA2D, FA2BASE, FA2TOP, transfer);
btn[0] = (char)s->b[0];
btn[1] = (char)s->b[1];
do_btns (p, btn, rangeof (btn));
return (0);
}
LOCAL_FUNC int FAR
JsbCal (POINTER *p)
{
STICK s[1];
int m;
m = JS_X1|JS_Y1;
m = JsInput (1, s, FOPTS, (Ushort)m, 10, 10);
if (m & JS_X1)
return (1);
if (!s->a[0])
return (2);
if (m & JS_Y1)
return (3);
if (!s->a[1])
return (4);
FA1BASE = p->low[FA1F];
FA1TOP = p->high[FA1F];
p->c[FA1F] = s->a[0];
p->play[FA1F] = muldiv (FA1TOP, FA1IDLE, 100);
p->a[FA1F] = p->l[FA1F] = 0;
p->low [FA1F] = 0x7fff;
p->high[FA1F] = 0x0000;
FA2BASE = p->low[FA2F];
FA2TOP = p->high[FA2F];
p->c[FA2F] = s->a[1];
p->play[FA2F] = muldiv (FA2TOP, FA2IDLE, 100);
p->a[FA2F] = p->l[FA2F] = 0;
p->low [FA2F] = 0x7fff;
p->high[FA2F] = 0x0000;
FOPTS |= CALIBRATED;
return (0);
}
LOCAL_FUNC int FAR
JsbInit (POINTER *p, char *options)
{
int ret;
FOPTS |= USETIMER;
JsOptions (p, options);
if (initstick (1, options, FOPTS))
return (1);
JsbCal (p); /* one for the road */
FOPTS &= ~CALIBRATED;
ret = JsbCal (p);
FOPTS &= ~CALIBRATED;
if (ret)
LogPrintf ("Bstick cal failed %d\n", ret);
else {
MsgWPrintf (200, "Move the stick to all 4 egdes,");
MsgWPrintf (200, " then center it.");
MsgWPrintf (200, "now hit 'x' to callibrate.");
}
return (ret);
}
LOCAL_FUNC void FAR
JsbTerm (POINTER *p)
{
termstick (1, FOPTS);
}
struct PtrDriver NEAR PtrAstick = {
"ASTICK",
0,
NULL, /* extra */
JsaInit,
JsaTerm,
JsaCal,
JsCenter,
JsaRead,
std_key
};
struct PtrDriver NEAR PtrBstick = {
"BSTICK",
0,
NULL, /* extra */
JsbInit,
JsbTerm,
JsbCal,
JsCenter,
JsbRead,
std_key
};
#undef PO
#undef FA1D
#undef FA1F
#undef FA2D
#undef FA2F
#undef FNREAD
#undef FDELAY
#undef FA1IDLE
#undef FA1BASE
#undef FA1TOP
#undef FA2IDLE
#undef FA2BASE
#undef FA2TOP
#undef FA3IDLE
#undef FA3BASE
#undef FA3TOP
#undef FA4IDLE
#undef FA4BASE
#undef FA4TOP
#undef FOPTS
#undef REF
#undef REFDETENT
#endif /* ifdef HAVE_JOYSTICK */